package com.chentongwei.common.aop;

import com.chentongwei.common.constant.ResponseEnum;
import com.chentongwei.common.entity.Result;
import com.chentongwei.common.exception.BussinessException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;

import java.util.List;

/**
 * AOP拦截Service层，记录慢日志。
 *
 * @author TongWei.Chen 2017-9-17 16:58:13
 */
@Aspect
@Component
public class LogAOP {

    private static final Logger LOG = LoggerFactory.getLogger("slowLog");//慢日志
    private static final Logger EXCEPTION_LOG = LoggerFactory.getLogger("exceptionLog"); //异常日志

    private static final String CUT = "execution (* com.chentongwei.core.*.biz.*Biz.*(..))";//切点表达式

    @Around(CUT)
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        long start = System.currentTimeMillis();

        Result result = new Result();
        StringBuilder sb = new StringBuilder();

        try {
            result = (Result)pjp.proceed(args);
        } catch (Throwable e) {
            resolverException(e, sb, result);
            e.printStackTrace();
            EXCEPTION_LOG.error("程序出现异常：" + sb, e);
            result.setResult(sb);
        }
        //慢日志
        long end = System.currentTimeMillis();
        if (end - start >= 2000) {//大于一秒记录
            LOG.info("method [" + pjp.getSignature().toString() +"] cost " + (end - start) + "ms ---------------");
        }
        return result;
    }

    /*
     * 处理异常
     */
    private void resolverException(Throwable e, StringBuilder sb, Result result) {
        if(e instanceof BussinessException) {
            resolverBussinessException(e, sb, result);
        } else if (e instanceof BindException) {
            resolverBindException(e, sb, result);
        } else {
            resolverOtherException(e, sb, result);
        }
    }

    /*
     * 处理业务层异常
     */
    private void resolverBussinessException(Throwable e, StringBuilder sb, Result result) {
        BussinessException businessException = (BussinessException) e;
        sb.append(businessException.getResponseEnum().getMsg());
        addResult(result, businessException.getResponseEnum().getCode(), businessException.getResponseEnum().getMsg());
    }

    /*
    * 处理参数绑定异常
    */
    private void resolverBindException(Throwable e, StringBuilder sb, Result result) {
        BindException be = (BindException) e;
        List<FieldError> errorList = be.getBindingResult().getFieldErrors();
        for (FieldError error : errorList) {
            sb.append(error.getObjectName());
            sb.append("对象的");
            sb.append(error.getField());
            sb.append("字段");
            sb.append(error.getDefaultMessage());
        }
        addResult(result, ResponseEnum.PARAM_ERROR.getCode(), ResponseEnum.PARAM_ERROR.getMsg());
    }

    /*
     * 处理其他异常
     */
    private void resolverOtherException(final Throwable e, StringBuilder sb, Result result) {
        sb.append(e.getMessage());
        addResult(result, ResponseEnum.FAILED.getCode(), ResponseEnum.FAILED.getMsg());
    }

    /*
     * 封装code和msg
     */
    private void addResult(Result result, final int code, final String msg) {
        result.setCode(code);
        result.setMsg(msg);
    }

}